package com.lagou.client;

import com.lagou.handler.UserClientHandler;
import com.lagou.service.*;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 消费者
 */
public class RPCConsumer {
        //1,创建一个线程池对象  --它要处理我们自定义事件
        private static ExecutorService executorService=
                Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

        //2,声明一个自定义事件处理器 UserClientHandler
        private static UserClientHandler userClientHandler;

        //3,编写方法 初始化客户端（创建连接池 bootstrap 设置bootstrap 连接服务器）
        public static void initClient() throws InterruptedException {
            //1),初始化UserClientHandler
            userClientHandler=new UserClientHandler();
            //2),创建连接池对象
            EventLoopGroup group =new NioEventLoopGroup();
            //3),创建客户端的引导对象
            Bootstrap bootstrap=new Bootstrap();
            //4),配置启动引导对象
            bootstrap.group(group)
                    //设置管道NIO
                    .channel(NioSocketChannel.class)
                    //设置请求协议TCP
                    .option(ChannelOption.TCP_NODELAY,true)
                    //监听channel并初始化
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //获取ChannelPipeline
                            ChannelPipeline pipeline = ch.pipeline();
                            //pipeline.addLast(new StringEncoder());
                            pipeline.addLast( new RpcEncoder(RpcRequest.class, new JSONSerializer()));
                            pipeline.addLast(new StringDecoder());
                            //pipeline.addLast( new RpcDecoder(RpcRequest.class, new JSONSerializer()));
                            //添加自定义处理事件
                            pipeline.addLast(userClientHandler);
                        }
                    });
            //5)连接服务端
            bootstrap.connect("127.0.0.1",8999).sync();
        }


    /**
     * 使用jdk动态代理 1，初始化客户端  2，向服务端请求数据 并且返回数据
      * @param serviceClass
     */
    public static Object createProxy(Class<IUserService> serviceClass) {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{serviceClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                //1,初始化客户端client
                initClient();

                //2,给UserClientHandler 设置param参数
                //封装
                RpcRequest request = new RpcRequest();
                String requestId = UUID.randomUUID().toString();
                System.out.println(requestId);

                String className = method.getDeclaringClass().getName();
                String methodName = method.getName();

                Class<?>[] parameterTypes = method.getParameterTypes();

                request.setRequestId(requestId);
                request.setClassName(className);
                request.setMethodName(methodName);
                request.setParameterTypes(parameterTypes);
                request.setParameters(objects);



                // 设置参数
                userClientHandler.setParam(request);
                System.out.println(request);
                System.out.println("设置参数完成");



                //userClientHandler.setParam(providerName+objects[0]);
                //3,使用线程池，开启一个线程处理call()方法写操作 并返回结果
                Object result = executorService.submit(userClientHandler).get();
                return result;
            }
        });
    }
}
